﻿using DynamicAuthorization.Sdk.Abstarctions;
using DynamicAuthorization.Sdk.Exceptions;
using Microsoft.Extensions.Caching.Memory;
using System.Reflection;

namespace DynamicAuthorization.Sdk.Impl;

internal sealed class GrantService : IGrantService
{
    private readonly IMemoryCache _cache;

    public GrantService(IMemoryCache cache)
    {
        _cache = cache;
    }

    public IGrantTypeMetadata Analyze(string grant)
    {
        if (!string.IsNullOrEmpty(grant))
        {
            var hashGrant = grant.GetHashCode();

            if (!_cache.TryGetValue<IGrantTypeMetadata>(hashGrant, out var metadata))
            {
                metadata = new GrantTypeMetadata(grant);

                _cache.Set(hashGrant, metadata);
            }

            return metadata;
        }

        return GrantTypeMetadata.Empty;
    }

    public bool Check(string grant, Type controller, MethodInfo action)
    {
        if (grant == "#")
        {
            return true;
        }

        var hashGrant = grant.GetHashCode();

        if (!_cache.TryGetValue<IGrantTypeMetadata>(hashGrant, out var metadata))
        {
            metadata = new GrantTypeMetadata(grant);

            _cache.Set(hashGrant, metadata);
        }
        try
        {
            var @class = metadata.MapClass(controller);

            return @class is not null || metadata.MapMethod(controller, action) is not null || metadata.IsAdmin;
        }
        catch (RejectedAccessException)
        {
            return false;
        }
    }
}